package gormtest

import (
	"crypto/rand"
	"errors"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	r "math/rand"
	"sync"
	"time"
)

type Catalog struct {
	CataId       string    `json:"cata_id" gorm:"primaryKey"`
	CataCode     string    `json:"cata_code"`
	Name         string    `json:"name"`
	ParentCataId string    `json:"parent_cata_id"`
	Path         string    `json:"path"` //eg: cata_root.cata_iaas.cata_host
	DisplayOrder uint32    `json:"display_order"`
	Level        uint32    `json:"level"`
	AccessSysId  string    `json:"access_sys_id"`
	CreateTime   time.Time `json:"create_time"`
	UpdateTime   time.Time `json:"update_time"`
	CreatedBy    string    `json:"created_by"`
}

func (*Catalog)TableName() string {
	return "catalog"
}

func Db() (db *gorm.DB) {
	var (
		err error
	)
	dsn := "root:p@ss52Dnb@tcp(192.168.49.2:32306)/pricing?parseTime=1&multiStatements=1&charset=utf8mb4&collation=utf8mb4_unicode_ci"
	if db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		PrepareStmt: false,
	}); err != nil {
		log.Fatal(err)
	}

	sqlDB, err := db.DB()
	if err != nil {
		log.Fatal(err)
	}

	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)

	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)

	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)

	return
}

func CreateCate() {

	db:=Db()

	db.Transaction(func(tx *gorm.DB) error {
		// 在事务中执行一些 db 操作（从这里开始，您应该使用 'tx' 而不是 'db'）

		w:=new(sync.WaitGroup)
		for i:=0;i<3;i++ {
			w.Add(1)
			go func() {
				defer w.Done()
				err:=createCate(tx,&Catalog{
					CataId:       getRandString(),
					Name:         getRandString(),
				})

				if err != nil {
					log.Println(">>>>",err)
				}

			}()
		}

		w.Wait()

		// 返回 nil 提交事务
		return errors.New("rollback")
	})

}

func createCate(db *gorm.DB,cate *Catalog) (err error) {

	var count int64
	if err=db.Model(cate).Where("cata_id != ?" ,cate.CataId).Where("name",cate.Name).Count(&count).Error;err!= nil {
		return errors.New("名称重复")
	}

	if err=db.Create(cate).Error;err!= nil {
		return
	}

	return
}

var alphaNum = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`)

// RandomCreateBytes generate random []byte by specify chars.
func RandomCreateBytes(n int, alphabets ...byte) []byte {
	if len(alphabets) == 0 {
		alphabets = alphaNum
	}
	var bytes = make([]byte, n)
	var randBy bool
	if num, err := rand.Read(bytes); num != n || err != nil {
		r.Seed(time.Now().UnixNano())
		randBy = true
	}
	for i, b := range bytes {
		if randBy {
			bytes[i] = alphabets[r.Intn(len(alphabets))]
		} else {
			bytes[i] = alphabets[b%byte(len(alphabets))]
		}
	}
	return bytes
}

func getRandString()  string{
	return string(RandomCreateBytes(16))
}